package com.ottoman.snackgames;

import java.util.ArrayList;

import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.World;

public class Sketch extends ShapeRenderer{

	public int scale = 30; // must be >=2 to render correctly
	public int mazeWidth = 15; // width in # of cells
	public int mazeHeight = 10; // height in # of cells
	public int spacing = 10; //size of border around maze in pixels
	
	public Maze maze = new Maze(mazeWidth, mazeHeight); //the maze

	public ArrayList<Wall> walls;	//a list of all walls in the maze
	public ArrayList<CellSet> sets = new ArrayList<CellSet>(); //all the CellSets
	public ArrayList<Body> bodies = new ArrayList<Body>();	
	Cell c; //to hold the active Cell
	Cell cNext; //to hold another Cell
    private World _world;
	
	public void setup() {
		//size(spacing * 2 + scale * mazeWidth, spacing * 2 + scale * mazeHeight);
		//Cannot build processing applet with variables in the size() method, oh well
		
		maze.getCell(mazeWidth - 1, mazeHeight - 1).setEnd(); // set bottom right Cell as END point - only effects drawing
		maze.getCell(0, 0).setStart(); //mark top left cell as START point - only effects drawing
		
		//easier access
		walls = maze.walls;
		
		//create all CellSets
		for(int y = 0 ; y < mazeHeight ; y++){
			for(int x = 0 ; x < mazeWidth ; x++){
				sets.add(new CellSet(maze.getCell(x, y)));
			}
		}
		
		
		
	}

	public void draw() { //automatically loops at specified frameRate
		//background(0); //black out background (clearing any drawing)
		//maze.drawMaze(this); //draw the maze
		
		if (sets.size()!=1) { //if there is only one set, the maze is done
			Wall w = (Wall) Rand.pickRandom(walls); //pick a random wall
			CellSet setA = getSetContaining(w.a); //get the set with one of the Cells for that wall...
			CellSet setB = getSetContaining(w.b);//and then get one for the other
			if(setA != setB){ //if the two Cells are in different sets
				w.tearDown(); //tear down the wall between them
				setA.add(setB); //union the two sets by adding setB to setA...
				sets.remove(setB); //and getting removing setB from the set list
			}
			walls.remove(w); //remove that wall so it doesn't come up again
		} else { //maze is finished
			//noLoop(); //stop looping the draw() method
			//maze.drawMaze(this); //draw the maze
			//put green border to indicate completion
			//noFill();
			//stroke(color(0,255,0));
			//shape.begin(ShapeType.Box);
			//shape.rect(0, 0, width - 1, height - 1);
			//rect(0,0,width-1,height-1);
			//shape.end();
		}
	}
	
	public boolean builtForDraw() { //automatically loops at specified frameRate
		//background(0); //black out background (clearing any drawing)
		//maze.drawMaze(this); //draw the maze
		
		if (sets.size()!=1) { //if there is only one set, the maze is done
			Wall w = (Wall) Rand.pickRandom(walls); //pick a random wall
			CellSet setA = getSetContaining(w.a); //get the set with one of the Cells for that wall...
			CellSet setB = getSetContaining(w.b);//and then get one for the other
			if(setA != setB){ //if the two Cells are in different sets
				w.tearDown(); //tear down the wall between them
				setA.add(setB); //union the two sets by adding setB to setA...
				sets.remove(setB); //and getting removing setB from the set list
			}
			walls.remove(w); //remove that wall so it doesn't come up again
			return false;
		} else { //maze is finished
			return true;
		}
	}
	
	
	//get the set in sets containing the given Cell. There is always only one.
	public CellSet getSetContaining(Cell c){
		for(CellSet cs : sets){
			if(cs.memberOf(c)){
				return cs;
			}
		}
		return null;
	}
	
	public void setWorld(World w){
		_world = w;
	}
	
	public void builtMazeBody(){
       while(!builtForDraw()){
			
		}
		 
		for(int i=0;i<mazeWidth;i++){
			for(int j=0;j<mazeHeight;j++){
				Cell c = maze.getCell(i, j);
				
		        
				int originx = 2 + c.getX() * scale;
				int originy = 2 + c.getY() * scale;
		        
		        
				if (!c.getStart() && (c.northWall==null || c.northWall.isUp())){//yatay
					//s.line(originx, originy, originx + s.scale, originy);
					makeWallBody(originx + scale, originy, scale, 2);
				}
				if (!c.getEnd() && (c.southWall==null || c.southWall.isUp())){//yatay
					//s.line(originx, originy + s.scale, originx + s.scale, originy + s.scale);
					makeWallBody(originx + scale, originy + scale, scale, 2);
				}
				if (c.eastWall==null || c.eastWall.isUp()){//dikey
					//s.line(originx + s.scale, originy, originx + s.scale, originy + s.scale);
					makeWallBody(originx + scale, originy + scale, 2, scale);
				}
				if (c.westWall==null || c.westWall.isUp()){//dikey
					//s.line(originx, originy, originx, originy + s.scale);
					makeWallBody(originx, originy + scale, 2, scale);
				}
			}
		}
		
	}
	
	private void makeWallBody(int posX, int posY, int w, int h){
		MazeWorld sm = new MazeWorld();
		
		BodyDef bodyDef = new BodyDef();
		bodyDef.type = BodyType.StaticBody;
        FixtureDef fixDef = new FixtureDef();				
        fixDef.friction = 0.5f;                 
        fixDef.restitution =0.02f;  
        PolygonShape pol = new PolygonShape();
		pol.setAsBox(w * sm.PIX_TO_METER / 2, h * sm.PIX_TO_METER / 2);
        fixDef.shape = pol;
		bodyDef.position.set(posX * sm.PIX_TO_METER -((w) * sm.PIX_TO_METER / 2) + ((scale / 2)* sm.PIX_TO_METER), posY * sm.PIX_TO_METER - ((h) * sm.PIX_TO_METER / 2) + ((scale / 2) * sm.PIX_TO_METER));
		Body b = _world.createBody(bodyDef);
		b.createFixture(fixDef);
		b.setUserData(new Vector2(w, h));
		bodies.add(b);
	}
}